<!DOCTYPE html>
<html>

<head>
  <!-- <meta charset="utf-8"> -->
  <meta name="viewport"
    content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no" />
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bulma@0.9.2/css/bulma.min.css">
  <script src="https://cdn.jsdelivr.net/npm/@mediapipe/camera_utils@0.1/camera_utils.js" crossorigin="anonymous">
  </script>
  <script src="https://cdn.jsdelivr.net/npm/@mediapipe/control_utils@0.1/control_utils.js" crossorigin="anonymous">
  </script>
  <script src="https://cdn.jsdelivr.net/npm/@mediapipe/drawing_utils@0.2/drawing_utils.js" crossorigin="anonymous">
  </script>
  <script src="https://cdn.jsdelivr.net/npm/@mediapipe/pose@0.2/pose.js" crossorigin="anonymous"></script>
</head>

<body>
  <div class="container" style="margin-top: 20px;">
    <video class="input_video5" style="display: none;" width="800px" height="600px"></video>
    <canvas class="output5" width="800px" height="600px"></canvas>
    <div class="loading" div class="spinner"></div>
  </div>
  <button onclick="testRecord();alert('开始录像');">测试录像</button>
  <button onclick="testPause();">测试暂停</button>
  <button onclick="download();">测试下载</button>
  <audio id="audiotest" style="display: none;"></audio>
  <p id="tips" style="font-size:22px;font-weight:bold">正在加载，请稍候</p>
  <div style="visibility: hidden;display: none;" class="control5"></div>
  </div>
  <script>
    const video5 = document.getElementsByClassName('input_video5')[0];
    const out5 = document.getElementsByClassName('output5')[0];
    const controlsElement5 = document.getElementsByClassName('control5')[0];
    const canvasCtx5 = out5.getContext('2d');

    const stream = out5.captureStream();
    const options = { mimeType: 'video/webm;codecs=vp8,opus' };
    var recordedChunks = [];
    const mediaRecorder = new MediaRecorder(stream, options);
    console.log(mediaRecorder);
    var allow_count = false;
    video5.addEventListener("canplaythrough", () => {
      console.log("video ok");
      window.parent.postMessage("ok", "*")
    })

    const fpsControl = new FPS();
    const spinner = document.querySelector('.loading');
    var score = 0,
      flag_1 = 0;
    spinner.ontransitionend = () => {
      spinner.style.display = 'none';
    };

    function zColor(data) {
      const z = clamp(data.from.z + 0.5, 0, 1);
      return `rgba(0, ${255 * z}, ${255 * (1 - z)}, 1)`;
    }

    function onResultsPose(results) {
      document.body.classList.add('loaded');
      fpsControl.tick();
      canvasCtx5.save();
      canvasCtx5.clearRect(0, 0, out5.width, out5.height);
      canvasCtx5.drawImage(
        results.image, 0, 0, out5.width, out5.height);
      document.getElementById("tips").innerHTML = "加载完成";
      var i, flag_detect = 0;
      if (results.poseLandmarks == undefined) {
        flag_detect = 1;
        canvasCtx5.font = '20px Arial';      //设置字号和字体
        canvasCtx5.fillStyle = '#FF0000';  //设置字体颜色
        canvasCtx5.fillText('无法检测，请将全身置入相机画面！', 400, 20);
      } else {
        for (i = 0; i < 33; i++) {
          if (results.poseLandmarks[i].x >= 1 || results.poseLandmarks[i].y >= 1) {
            flag_detect = 1;
            canvasCtx5.font = '20px Arial';      //设置字号和字体
            canvasCtx5.fillStyle = '#FF0000';  //设置字体颜色
            canvasCtx5.fillText('无法检测，请将全身置入相机画面！', 400, 20);
            break;
          }
        }
      }

      if (flag_detect == 0) {
        //可以开始进行俯卧撑的判断
        //分情况使用不同的点 头在画面左边使用左边身体的点 头在画面右边使用右边身体的点
        if (results.poseLandmarks[POSE_LANDMARKS.NOSE].x <= results.poseLandmarks[POSE_LANDMARKS.LFET_SHOULDER]) {
          Point_shoulder = {
            X: results.poseLandmarks[POSE_LANDMARKS.LFET_SHOULDER].x * video5.width,
            Y: results.poseLandmarks[POSE_LANDMARKS.LFET_SHOULDER].y * video5.height
          };
          Point_hip = {
            X: results.poseLandmarks[POSE_LANDMARKS.LFET_HIP].x * video5.width,
            Y: results.poseLandmarks[POSE_LANDMARKS.LFET_HIP].y * video5.height
          };
          Point_ankle = {
            X: results.poseLandmarks[POSE_LANDMARKS.LFET_ANKLE].x * video5.width,
            Y: results.poseLandmarks[POSE_LANDMARKS.LFET_ANKLE].y * video5.height
          };
          Point_elbow = {
            X: results.poseLandmarks[POSE_LANDMARKS.LFET_ELBOW].x * video5.width,
            Y: results.poseLandmarks[POSE_LANDMARKS.LFET_ELBOW].y * video5.height
          };
          Point_wrist = {
            X: results.poseLandmarks[POSE_LANDMARKS.LFET_WRIST].x * video5.width,
            Y: results.poseLandmarks[POSE_LANDMARKS.LFET_WRIST].y * video5.height
          };
        } else {
          Point_shoulder = {
            X: results.poseLandmarks[POSE_LANDMARKS.RIGHT_SHOULDER].x * video5.width,
            Y: results.poseLandmarks[POSE_LANDMARKS.RIGHT_SHOULDER].y * video5.height
          };
          Point_hip = {
            X: results.poseLandmarks[POSE_LANDMARKS.RIGHT_HIP].x * video5.width,
            Y: results.poseLandmarks[POSE_LANDMARKS.RIGHT_HIP].y * video5.height
          };
          Point_ankle = {
            X: results.poseLandmarks[POSE_LANDMARKS.RIGHT_ANKLE].x * video5.width,
            Y: results.poseLandmarks[POSE_LANDMARKS.RIGHT_ANKLE].y * video5.height
          };
          Point_elbow = {
            X: results.poseLandmarks[POSE_LANDMARKS.RIGHT_ELBOW].x * video5.width,
            Y: results.poseLandmarks[POSE_LANDMARKS.RIGHT_ELBOW].y * video5.height
          };
          Point_wrist = {
            X: results.poseLandmarks[POSE_LANDMARKS.RIGHT_WRIST].x * video5.width,
            Y: results.poseLandmarks[POSE_LANDMARKS.RIGHT_WRIST].y * video5.height
          };
        }
        //拿到点后开始判断角度
        angle1 = getAngle(Point_shoulder, Point_hip, Point_ankle);
        if (angle1 < 160) {
          drawLine(canvasCtx5, Point_shoulder.X, Point_shoulder.Y, Point_hip.X, Point_hip.Y, '#BF3F3F', 5);
          drawLine(canvasCtx5, Point_ankle.X, Point_ankle.Y, Point_hip.X, Point_hip.Y, '#BF3F3F', 5);
          if (Math.abs(Point_shoulder.Y - Point_hip.Y) > Math.abs(Point_ankle.Y - Point_hip.Y)) {
            canvasCtx5.font = '20px Arial';      //设置字号和字体
            canvasCtx5.fillStyle = '#558EF0';  //设置字体颜色
            canvasCtx5.fillText('请勿塌腰', 20, 160);
          } else {
            canvasCtx5.font = '20px Arial';      //设置字号和字体
            canvasCtx5.fillStyle = '#558EF0';  //设置字体颜色
            canvasCtx5.fillText('请绷直身体', 20, 160);
          }
        } else {
          if (allow_count) {
            //开始判断是否完成一次俯卧撑
            //angle2是肩膀、脚踝、肩膀X脚踝Y三点所成的角度
            angle2 = getAngle(Point_shoulder, Point_ankle, {
              X: Point_shoulder.X,
              Y: Point_ankle.Y
            });
            angle3 = getAngle(Point_shoulder, Point_elbow, Point_wrist);
            //判断是否完成一次俯卧撑的条件
            //1、angle2<10度
            //2、肩膀、肘部和手腕所成的角度尽量小
            if (flag_1 == 1) { //可以计数状态
              if (angle2 < 10 && angle3 < 120) {
                score += 1;
                if (score % 1 == 0) {
                  playByInput(score);
                } // 此处修改每计数几次语音播报一次
                flag_1 = 0;
              }
            }
            if (flag_1 == 0) { //不可计数状态
              if (angle2 > 15 && angle3 > 150) {
                flag_1 = 1;
              }
            }
          }
        }
      } else {
        canvasCtx5.font = '20px Arial';      //设置字号和字体
        canvasCtx5.fillStyle = '#558EF0';  //设置字体颜色
        canvasCtx5.fillText('人物在画面范围外', 20, 160);
        // tips_pic = "人物在画面范围外";
      }
      canvasCtx5.font = '24px Arial';      //设置字号和字体
      canvasCtx5.fillStyle = '#FFFFFF';  //设置字体颜色
      canvasCtx5.fillText('计数:' + score, 20, 40);
    }

    //画线函数
    function drawLine(canvasObj, x1, y1, x2, y2, strokeStyle, lineWidth) {
      canvasObj.beginPath(); //开始画线
      canvasObj.moveTo(x1, y1); //画线起点
      canvasObj.lineTo(x2, y2); //画线终点
      canvasObj.strokeStyle = strokeStyle; //画线颜色:'#FFFFFF'
      canvasObj.lineWidth = lineWidth; //画线粗细，数字
      canvasObj.stroke(); //画线
      canvasObj.closePath(); //结束画线
    }

    //获取三点所成直线角度
    function getAngle(B, A, C) {
      var AB = Math.sqrt(Math.pow(A.X - B.X, 2) + Math.pow(A.Y - B.Y, 2));
      var AC = Math.sqrt(Math.pow(A.X - C.X, 2) + Math.pow(A.Y - C.Y, 2));
      var BC = Math.sqrt(Math.pow(B.X - C.X, 2) + Math.pow(B.Y - C.Y, 2));
      var cosA = (
        Math.pow(AB, 2) + Math.pow(AC, 2) - Math.pow(BC, 2)
      ) / (
          2 * AB * AC
        );
      var angleA = Math.round(Math.acos(cosA) * 180 / Math.PI);
      return angleA;
      // 得到angleA角度：45°

      /*
          AB      = 开根( (A.X-B.X)² + (A.Y-B.Y)² ）
          AC      =       A.X-C.X      A.Y-C.Y
          BC      =       B.X-C.X      B.Y-C.Y
          cosA   = (AB²+AC²-BC²) / (2*AB*AC)
          angleA  = Math.acos(cosA)*180/Math.PI
      */
    }

    // 音频播放的相关部分——开始位置
    let ponit = 0, playList = []
    audio = document.getElementById("audiotest")
    audio.addEventListener("ended", () => {
      playAudio()
    })

    function playByInput(value) {
      // let value = Number(document.getElementById("input").value)
      let arr = []
      while (value) {
        // console.log(value);
        if (value >= 10000) {
          arr.push(Math.floor(value / 10000), "万")
          value = value % 10000
          if (value < 1000 && value > 0) arr.push(0)
        }
        else if (value >= 1000) {
          arr.push(Math.floor(value / 1000), "千")
          value = value % 1000
          if (value < 100 && value > 0) arr.push(0)
        } else if (value >= 100) {
          arr.push(Math.floor(value / 100), "百")
          value = value % 100
          if (value < 10 && value > 0) arr.push(0)
        } else if (value >= 10) {
          arr.push(Math.floor(value / 10), 10)
          value = value % 10
        } else if (value > 0) {
          arr.push(value)
          break
        }
        if (value === 0) break
      }
      if (arr.length == 2) {
        if (arr[arr.length - 2] == 1) arr.splice(arr.length - 2, 1)
      }
      playList = arr
      ponit = 0
      console.log(playList);
      playAudio()
    }

    function playAudio() {
      if (ponit === playList.length) return
      audio.src = `./${playList[ponit]}.mp3`
      audio.play()
      ponit++
    }

    const pose = new Pose({
      locateFile: (file) => {
        return `https://cdn.jsdelivr.net/npm/@mediapipe/pose@0.2/${file}`;
      }
    });
    pose.onResults(onResultsPose);

    function testRecord() {
      allow_count = true;
      mediaRecorder.ondataavailable = handleDataAvailable;
      mediaRecorder.start();
      function handleDataAvailable(event) {
        console.log("data-available");
        if (event.data.size > 0) {
          recordedChunks.push(event.data);
          console.log(recordedChunks);
          // download();
        } else {
          // ...
        }
      }
    }

    function download() {
      var blob = new Blob(recordedChunks, {
        type: "video/webm"
      });
      var url = URL.createObjectURL(blob);
      console.log(url);
      var a = document.createElement("a");
      document.body.appendChild(a);
      a.style = "display: none";
      a.href = url;
      a.download = "test.webm";
      a.click();
      window.URL.revokeObjectURL(url);
      recordedChunks = [];
      // 加这一句则清空之前的录像
    }

    function testPause() {
      allow_count = false;
      mediaRecorder.stop();
      // download();
      // recordedChunks = [];
    }

    const camera = new Camera(video5, {
      onFrame: async () => {
        await pose.send({
          image: video5
        });
      },
      width: video5.width,
      height: video5.height,
      facingMode: "environment"
    });
    camera.start();
    console.log(camera);
    new ControlPanel(controlsElement5, {
      selfieMode: false,
      upperBodyOnly: false,
      smoothLandmarks: true,
      minDetectionConfidence: 0.8,
      minTrackingConfidence: 0.8
    })
      .add([
        new StaticText({
          title: 'MediaPipe Pose'
        }),
        fpsControl,
        new Toggle({
          title: 'Selfie Mode',
          field: 'selfieMode'
        }),
        new Toggle({
          title: 'Upper-body Only',
          field: 'upperBodyOnly'
        }),
        new Toggle({
          title: 'Smooth Landmarks',
          field: 'smoothLandmarks'
        }),
        new Slider({
          title: 'Min Detection Confidence',
          field: 'minDetectionConfidence',
          range: [0, 1],
          step: 0.01
        }),
        new Slider({
          title: 'Min Tracking Confidence',
          field: 'minTrackingConfidence',
          range: [0, 1],
          step: 0.01
        }),
      ])
      .on(options => {
        video5.classList.toggle('selfie', options.selfieMode);
        pose.setOptions(options);
      });
  </script>
</body>

</html>